﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vowei.Core.Models;
using System.IO;
using Vowei.Core;
using NPOI.HSSF.UserModel;
using System.Diagnostics;
using Vowei.Converters;

namespace Vowei.Data.Converters.Excel
{
    public class ResourceAssignmentDetail
    {
        public ResourceAssignment Assignment { get; set; }

        public Employee Employee { get; set; }
    }

    public class AssignmentExcelConverter : ExcelConverter<IEnumerable<ResourceAssignmentDetail>>
    {
        private UserExcelConverter _userConverter;
        public AssignmentExcelConverter(UserExcelConverter userConverter, ITranslator translator)
            : base(translator)
        {
            _userConverter = userConverter;
        }

        public AssignmentExcelConverter(UserExcelConverter userConverter)
            : this(userConverter, DefaultTranslator)
        {
        }

        public override bool CanConvert(Stream stream)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");
            if (Translator == null)
                throw new InvalidOperationException(DefaultTranslator.T("在从Excel导入数据之前，请指定用户转换日期、数字、货币等格式的区域设置！"));

            var memoryStream = new MemoryStream((int)stream.Length);
            stream.CopyTo(memoryStream);
            var workbook = new HSSFWorkbook(memoryStream);
            var sheet = GetWorkItemsSheet(workbook);
            var firstRow = GuessFirstRow(sheet, Translator.T<ResourceAssignment, float>(r => r.CostPerHour), false);
            return firstRow >= 0;
        }

        public override IEnumerable<ResourceAssignmentDetail> ConvertFrom(Stream stream)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");
            if (Translator == null)
                throw new InvalidOperationException(DefaultTranslator.T("在从Excel导入数据之前，请指定用户转换日期、数字、货币等格式的区域设置！"));

            var memoryStream = new MemoryStream((int)stream.Length);
            stream.CopyTo(memoryStream);
            memoryStream.Position = 0;
            var users = _userConverter.ConvertFrom(memoryStream);
            var employees = users as List<Employee>;

            memoryStream.Position = 0;
            var workbook = new HSSFWorkbook(memoryStream);
            var sheet = workbook.GetSheet(WorkSheetName);
            if (sheet == null)
                sheet = workbook.GetSheetAt(0);
            var map = ReadColumnNames(sheet.GetRow(sheet.FirstRowNum), new string[] {
                Translator.T<ResourceAssignment, float>(m => m.CostPerHour), // "工时成本",
                Translator.T<Employee, string>(m => m.Email), // "Email",
                Translator.T<Employee, string>(m => m.UserName) // "User Account",
            });

            var result = new List<ResourceAssignmentDetail>();
            var emailComparer = new EmployeeComparer(e => e.Email);
            var userNameComparer = new EmployeeComparer(e => e.UserName);

            var sortedEmailEmpls = employees.ToArray();
            var sortedUserNameEmpls = employees.ToArray();
            Array.Sort(sortedEmailEmpls, (left, right) => string.CompareOrdinal(left.Email, right.Email));
            Array.Sort(sortedUserNameEmpls, (left, right) => string.CompareOrdinal(left.UserName, right.UserName));

            for (int i = sheet.FirstRowNum + 1; i < sheet.LastRowNum + 1; ++i)
            {
                var row = sheet.GetRow(i);

                try
                {
                    var ra = new ResourceAssignment()
                    {
                        CostPerHour = ReadCell<float>(row, map[Translator.T<ResourceAssignment, float>(m => m.CostPerHour)], false)
                    };
                    var email = ReadCell<string>(row, map[Translator.T<Employee, string>(m => m.Email)], false);
                    var username = ReadCell<string>(row, map[Translator.T<Employee, string>(m => m.UserName)], false);
                    int idx = -1;

                    if (!string.IsNullOrEmpty(email))
                    {
                        idx = Array.BinarySearch(sortedEmailEmpls, email, emailComparer);
                        ra.ResourceId = sortedEmailEmpls[idx].ID;
                        result.Add(new ResourceAssignmentDetail
                        {
                            Assignment = ra,
                            Employee = sortedEmailEmpls[idx]
                        });
                    }
                    else if (!string.IsNullOrEmpty(username))
                    {
                        idx = Array.BinarySearch(sortedUserNameEmpls, username, userNameComparer);
                        ra.ResourceId = sortedUserNameEmpls[idx].ID;
                        result.Add(new ResourceAssignmentDetail
                        {
                            Assignment = ra,
                            Employee = sortedUserNameEmpls[idx]
                        });
                    }

                    if (idx < 0)
                        throw new InvalidDataException(Translator.T("在该行里，既没有指定用户的电子邮件地址，也没有指定用户的windows域账号，无法导入资源配置信息！"));
                }
                catch (Exception e)
                {
                    Trace.TraceError(string.Format(Translator.T("在试图导入Excel文件的“{0}”工作表失败，第{1}行有误, 具体错误信息是：{2}"), sheet.SheetName, i + 1, e.Message), e);
                }
            }

            return result;
        }

        public override void ConvertTo(IEnumerable<ResourceAssignmentDetail> from, Stream to)
        {
            throw new NotSupportedException("尚不支持将资源分配情况导出到Excel里！");
        }
    }
}
